<?php
set_time_limit(0);

class PatchService extends AbstractService
{
    const PATCH_RESET_INIT_BUILDING     =   1;  // 重置初始数据
    /**
     * @var PatchService
     */
    private static $instance;

    /**
     * Get the instance of PatchService.
     *
     * @return PatchService
     */
    public static function get()
    {
        if (!self::$instance) {
            self::$instance = new PatchService();
        }
        return self::$instance;
    }

    /**
     * Construction.
     */
    protected function __construct()
    {
        parent::__construct();
    }

    /**
     * 创建玩家帐号的同时，将玩家的Patch默认全部是最新的
     *
     * @param int $userId
     * @param ModuleProfileInfoVoList $profileInfoList
     * @return void
     */
    public function handleCreate($userId, $profileInfoList = null)
    {
        $reqTime = GameService::get()->getReqTime();

        if (!$profileInfoList) {
            $profileInfoList = SzPersister::get()->getVoList($userId, ModuleProfileConst::ORM_NAME_PROFILE_INFO);
        }

        $patchInfo = $profileInfoList->getElement(GameConst::USER_INFO_TYPE_PATCH_INFO, false);
        if (!$patchInfo) {
            $patchInfo = new ModuleProfileInfoVo($userId, // userId
                GameConst::USER_INFO_TYPE_PATCH_INFO, // infoType
                json_encode([]), // info
                $reqTime, // time
                true);
        }
        // update info
        $patchInfo->setInfo([
            self::PATCH_RESET_INIT_BUILDING => GameConst::DEFAULT_BOOL_OF_TRUE
        ]);
        $patchInfo->setTime($reqTime);

        // update info
        if ($patchInfo->isInsert() && !SzUtility::checkArrayKey(GameConst::USER_INFO_TYPE_PATCH_INFO, $profileInfoList->getList())) {
            $profileInfoList->addElement($patchInfo);
            $profileInfoList->setElement(GameConst::USER_INFO_TYPE_PATCH_INFO, $patchInfo);
        } else {
            $profileInfoList->updateElement(GameConst::USER_INFO_TYPE_PATCH_INFO, $patchInfo);
        }

        SzPersister::get()->setVoList($profileInfoList);
    }

    /**
     * 提供 Service 层的所有相关数据
     *
     * @param int $shardId
     * @return mixed
     */
    public function info($shardId)
    {
        return false;
    }

    /**
     * 用户登录，处理数据补丁
     *
     * @param int $userId
     * @param ModuleProfileVo $profile
     * @return void
     */
    public function handleLogin($userId, $profile = null)
    {
        // 当前启用的补丁
        $patchIds = [
            self::PATCH_RESET_INIT_BUILDING
        ];
        if (count($patchIds) == 0) {
            return;
        }

        $reqTime = GameService::get()->getReqTime();

        /**
         * @var ModuleProfileInfoVoList $profileInfoList
         * @var ModuleProfileInfoVo $profileInfo
         */
        $profileInfoList = SzPersister::get()->getVoList($userId, ModuleProfileConst::ORM_NAME_PROFILE_INFO);
        $patchInfo = $profileInfoList->getElement(GameConst::USER_INFO_TYPE_PATCH_INFO, false);

        if (!$patchInfo) {
            $patchInfo = new ModuleProfileInfoVo($userId, GameConst::USER_INFO_TYPE_PATCH_INFO, json_encode([]), $reqTime, true);
        }

        // 获取已经打过的补丁
        $patchedIds = $patchInfo->getRawInfo();

        $isPatched = false;
        foreach ($patchIds as $patchId) {
            // 已经处理过该补丁，无须再处理
            if (SzUtility::checkArrayKey($patchId, $patchedIds)) {
                continue;
            }
            // 根据补丁id，进行分类处理
            switch ($patchId) {
                case self::PATCH_RESET_INIT_BUILDING:
                    $this->resetInitBuilding($userId);
                    break;
            }

            // 补丁成功，更新结果
            $isPatched = true;
            $patchedIds[$patchId] = GameConst::DEFAULT_BOOL_OF_TRUE;
        }

        // 判断补丁数据是否由更新
        if ($isPatched) {
            $patchInfo->setInfo($patchedIds);

            if ($patchInfo->isInsert() && !SzUtility::checkArrayKey(GameConst::USER_INFO_TYPE_PATCH_INFO, $profileInfoList->getList())) {
                $profileInfoList->addElement($patchInfo);
                $profileInfoList->setElement(GameConst::USER_INFO_TYPE_PATCH_INFO, $patchInfo);
            } else {
                $profileInfoList->updateElement(GameConst::USER_INFO_TYPE_PATCH_INFO, $patchInfo);
            }
            SzPersister::get()->setVoList($profileInfoList);
        }
    }

    /**
     * 重置初始化装饰物数据
     * @param $userId
     * @return void
     */
    private function resetInitBuilding($userId)
    {
        $reqTime = GameService::get()->getSysTime();
        $blockResourceSettings = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GROUND_RESOURCE, null, true);
        $buildingSettings = SzConfig::get()->loadAppConfig(GameConst::CONFIG_BUILDING, null, true);

        $groundList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_GROUND);
        $buildingList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_BUILDING);

        $insertData = [];
        foreach ($blockResourceSettings as $resourceSetting) {
            if (!$resourceSetting['initialize']) {
                continue;
            }
            $buildingDefId = $resourceSetting['itemDefId'];
            $orient = $resourceSetting['direction'];
            $gridId = GroundService::get()->parseCoordinate($resourceSetting['anchorX'], $resourceSetting['anchorY']);

            /** @var GroundVo $ground */
            $ground = $groundList->getElement($gridId, false);
            if (!$ground) {
                $insertData[] = [$buildingDefId, $orient, $gridId];
                continue;
            }
            $decorId = $ground->getLayer($buildingSettings[$buildingDefId]['layer']);

            /** @var BuildingVo $building */
            $building = $buildingList->getElement($decorId, false);
            if (!$building) {
                $insertData[] = [$buildingDefId, $orient, $gridId];
                continue;
            }
            //只有当itemDefId或者orient有变化才修改
            if ($building->getBuildingDefId() == $buildingDefId  && $building->getOrient() == $orient) {
                continue;
            }
            $building->setOrient($orient);
            $building->setBuildingDefId($buildingDefId);
            $buildingList->updateElement($decorId, $building);
        }

        //插入没有的建筑
        foreach ($insertData as $buildingInfo) {
            list($buildingDefId, $orient, $gridId) = $buildingInfo;
            /** @var SzMySqlModel $buildingModel */
            $building = BuildingService::get()->create($userId, $buildingDefId, $orient, GameConst::DEFAULT_BOOL_OF_TRUE, GameConst::BUILDING_IS_BUILD, $reqTime);
            $buildingModel = SzPersister::get()->getModel(GameConst::ORM_NAME_BUILDING);
            list($affectedRows, $decorId) = $buildingModel->insert($building);
            if ($affectedRows) {
                $building->setDecorId($decorId);
                $building->removeInsertFlag();
                $buildingList->setElement($decorId, $building);
                $buildingModel->setListOfVoCache(array($building), $buildingList->getList());
                SzPersister::get()->addManuallyInsertedResponse($building, $userId, $decorId);
            }
            /** @var GroundVo $ground */
            $ground = $groundList->getElement($gridId, false);
            // 更新地块信息
            GroundService::get()->updateGroundWithGridId($userId, $gridId, $buildingSettings[$buildingDefId]['layer'], $decorId, $ground, $groundList, GameConst::GROUND_LAYER_TYPE_DECORATION);
        }
        SzPersister::get()->setVoList($groundList);
        SzPersister::get()->setVoList($buildingList);
    }
}
